<script setup>
import { ChunkUploader } from '@/utils/chunkUploader'
import { ElProgress } from 'element-plus'
import {
  Folder,
  Loading,
  SuccessFilled,
  CircleCloseFilled
} from '@element-plus/icons-vue'

const props = defineProps({
  extraParams: {
    type: Object,
    default: () => ({})
  }
})

const uploaderVisible = defineModel(false)

const uploadStatus = [
  {
    message: '上传中...',
    status: 'loading'
  },
  {
    message: '上传成功',
    status: 'success'
  },
  {
    message: '上传失败',
    status: 'error'
  }
]
const currentStatus = ref()
const currentMessage = computed(() => {
  return uploadStatus.find(item => item.status === currentStatus.value)?.message
})
const percentage = ref(0)

let uploader
const currentFile = shallowRef()

function disposeUploader() {
  if (uploader) {
    uploader.cancel()
    uploader = null
  }
}

function BtoMBOrGB(bytes) {
  const MB = bytes / 1024 / 1024
  const GB = MB / 1024
  return GB > 1 ? GB.toFixed(2) + 'GB' : MB.toFixed(2) + 'MB'
}

function updateStatus(status) {
  currentStatus.value = status
}

const fileInputRef = ref()
function selectFile() {
  fileInputRef.value?.click()
}

function reset() {
  currentFile.value = null
  percentage.value = 0
  updateStatus()
  // clear file input
  fileInputRef.value.value = ''
}

function handleFileChange(e) {
  const file = e.target.files[0]
  if (!file) return
  currentFile.value = file
  updateStatus()
  percentage.value = 0
}

function handleUpload() {
  if (!currentFile.value) return

  const baseUrl = import.meta.env.VITE_ORIGIN

  uploader = new ChunkUploader(currentFile.value, {
    chunkSize: 1024 * 1024 * 5, // 5MB
    url: baseUrl + '/upload/file/chunk',
    onProgress: progress => {
      percentage.value = progress
    },
    concurrentUploads: 3,
    extraParams: props.extraParams
  })

  percentage.value = uploader.progress

  doUpload()
}

function doUpload() {
  updateStatus('loading')
  uploader
    .upload()
    .then(() => {
      updateStatus('success')
    })
    .catch(() => {
      updateStatus('error')
    })
}

function retry() {
  doUpload()
}

async function handleClose(done) {
  if (currentStatus.value === 'loading') {
    await ElMessageBox.confirm('上传中，确定关闭吗?', '提示', {
      confirmButtonText: '确定',
      cancelButtonText: '取消',
      type: 'warning'
    })
    disposeUploader()
  }
  done()
}

onUnmounted(disposeUploader)
</script>

<template>
  <el-dialog
    v-model="uploaderVisible"
    width="768px"
    :close-on-click-modal="false"
    :close-on-press-escape="false"
    :before-close="handleClose"
    @open="reset"
  >
    <div class="flex items-center gap-2 px-2 py-4">
      <input
        ref="fileInputRef"
        type="file"
        accept="*/*"
        class="hidden"
        @change="handleFileChange"
      />
      <el-button type="primary" plain @click="selectFile">选择文件</el-button>

      <div v-if="currentFile">
        <span>{{ currentFile.name }}</span>
        <span class="ml-1 text-xs text-info">
          ({{ BtoMBOrGB(currentFile.size) }})
        </span>

        <el-button
          v-if="!currentStatus"
          type="primary"
          link
          @click="handleUpload"
        >
          确认上传
        </el-button>
      </div>
    </div>

    <div v-if="currentStatus">
      <div class="flex items-center gap-2 p-4">
        <el-icon :size="24"><Folder /></el-icon>
        <el-progress
          text-inside
          :percentage="percentage"
          :stroke-width="24"
          status="success"
          class="flex-1 [&_.el-progress\_\_text]:min-w-fit"
        />
      </div>
      <div class="text-center">
        <div class="flex flex-col justify-center gap-y-4 py-4">
          <div>
            <el-icon
              v-if="currentStatus === 'success'"
              :size="50"
              color="#67C23A"
            >
              <SuccessFilled />
            </el-icon>
            <el-icon
              v-else-if="currentStatus === 'error'"
              :size="50"
              color="#F56C6C"
            >
              <CircleCloseFilled />
            </el-icon>
            <el-icon
              v-else
              :size="50"
              color="#909399"
              class="animate-spin opacity-50 transition-transform"
            >
              <Loading />
            </el-icon>
          </div>
          <div class="text-lg">
            {{ currentMessage }}
          </div>
          <div>
            <el-button
              v-if="currentStatus === 'error'"
              type="primary"
              @click="retry"
            >
              重试
            </el-button>
          </div>
        </div>
      </div>
    </div>
  </el-dialog>
</template>
